package com.wtwd.campus.service.impl;


import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wtwd.campus.common.Constants;
import com.wtwd.campus.constant.DeviceFlagEnum;
import com.wtwd.campus.dao.DeviceFlagMapper;
import com.wtwd.campus.entity.*;
import com.wtwd.campus.hxy.service.CommandRecordService;
import com.wtwd.campus.model.dto.*;
import com.wtwd.campus.model.vo.DeviceFlagVo;
import com.wtwd.campus.service.DeviceFlagService;
import com.wtwd.campus.service.RedisService;
import com.wtwd.campus.utils.CommandNumberUtil;
import com.wtwd.campus.utils.CommandSendUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mjy
 * @since 2022-12-15
 */
@Service
public class DeviceFlagServiceImpl extends ServiceImpl<DeviceFlagMapper, DeviceFlag> implements DeviceFlagService {

    private static final Logger logger = LoggerFactory.getLogger(DeviceFlagServiceImpl.class);

    /**
     * 锁机锁网锁卡批量指令采用线程池处理
     */
    private static ExecutorService threadPool = new ThreadPoolExecutor(1,
            5,
            1L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(4),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());


    @Resource
    private DeviceFlagMapper deviceFlagMapper;

    @Resource
    private CommandSendUtils commandSendUtils;

    @Resource
    private RedisService redisService;


    @Resource
    private CommandRecordService commandRecordService;

    @Override
    public boolean setAppInstallationFlag(Integer deviceId, Integer flag) {
        return deviceFlagMapper.setAppInstallationFlag(deviceId, flag) > 0 ? true : false;
    }

    @Override
    public DeviceFlag queryDeviceSwitch(Integer deviceId) {
        return new LambdaQueryChainWrapper<>(deviceFlagMapper)
                .eq(DeviceFlag::getDeviceId, deviceId)
                .one();
    }

    @Override
    public boolean updateLockCardInfo(Integer deviceId, int flag, String pin, String iccid) {
        return deviceFlagMapper.updateLockCardInfo(deviceId, flag, pin, iccid) > 0 ? true : false;
    }

    @Override
    public boolean updateLockDeviceInfo(Integer deviceId, int flag, String iccid) {
        return deviceFlagMapper.updateLockDeviceInfo(deviceId, flag, iccid) > 0 ? true : false;
    }

    @Override
    public boolean updateLockNetInfo(Integer deviceId, int flag, List<Plmn> plmns) {
        return deviceFlagMapper.updateLockNetInfo(deviceId, flag, JSONArray.toJSONString(plmns)) > 0 ? true : false;
    }

    @Override
    public List<DeviceFlagVo> getDeviceLockCardInfoByOrgCode(String orgCode, Integer flag) {
        List<DeviceFlagVo> deviceFlagVos = deviceFlagMapper.getDeviceFlagByOrgCode(orgCode);
        if (deviceFlagVos != null) {
            DeviceFlagEnum deviceFlagEnum = DeviceFlagEnum.getDeviceFlagEnum(flag);
            deviceFlagVos = deviceFlagVos.stream().filter(e -> e.getCardFlag().equals(deviceFlagEnum.getFlag()) ||
                    e.getCardFlag().equals(deviceFlagEnum.getStayState()))
                    .collect(Collectors.toList());
        }
        return deviceFlagVos;
    }


    @Override
    public List<DeviceFlagVo> getDeviceLockDeviceInfoByOrgCode(String orgCode, Integer flag) {
        List<DeviceFlagVo> deviceFlagVos = deviceFlagMapper.getDeviceFlagByOrgCode(orgCode);
        if (deviceFlagVos != null) {
            DeviceFlagEnum deviceFlagEnum = DeviceFlagEnum.getDeviceFlagEnum(flag);
            deviceFlagVos = deviceFlagVos.stream().filter(e -> e.getLockDeviceFlag().equals(deviceFlagEnum.getFlag()) ||
                    e.getLockDeviceFlag().equals(deviceFlagEnum.getStayState()))
                    .collect(Collectors.toList());
        }
        return deviceFlagVos;
    }

    @Override
    public List<DeviceFlagVo> getDeviceLockNetInfoByOrgCode(String orgCode, Integer flag) {
        List<DeviceFlagVo> deviceFlagVos = deviceFlagMapper.getDeviceFlagByOrgCode(orgCode);
        if (deviceFlagVos != null) {
            DeviceFlagEnum deviceFlagEnum = DeviceFlagEnum.getDeviceFlagEnum(flag);
            deviceFlagVos = deviceFlagVos.stream().filter(e -> e.getLockNetFlag().equals(deviceFlagEnum.getFlag()) ||
                    e.getLockNetFlag().equals(deviceFlagEnum.getStayState()))
                    .collect(Collectors.toList());
        }
        return deviceFlagVos;
    }

    @Override
    public boolean bathLockCard(List<LockDto> lockDtos, SysUser sysUser) {
        if (lockDtos != null && lockDtos.size() > 0) {
            threadPool.submit(() -> {
                logger.info("线程: " + Thread.currentThread().getName() + " 开始执行 bathLockCard " + "执行指令用户id=" + sysUser.getUserId());
                List<String> imeis = lockDtos.stream().map(LockDto::getImei).collect(Collectors.toList());
                Map<String, Boolean> onlines = bathGetDeviceOnline(imeis);
                Iterator<LockDto> iterator = lockDtos.iterator();
                while (iterator.hasNext()) {
                    LockDto lockDto = iterator.next();
                    boolean rest = sendLockCard(lockDto.getImei(), lockDto.getFlag(), lockDto.getPin(), onlines.get(lockDto.getImei()), sysUser);
                    if (rest) {
                        lockDto.setFlag(DeviceFlagEnum.getDeviceFlagEnum(lockDto.getFlag()).getStayState());
                    } else {
                        iterator.remove();
                    }
                }
                bathCreateOrUpdateLockCardByLockDtos(lockDtos);
                logger.info("线程: " + Thread.currentThread().getName() + "执行结束 bathLockCard");
            });
        }
        return true;
    }

    @Override
    public boolean bathCreateOrUpdateLockCardByLockDtos(List<LockDto> lockDtos) {
        if (lockDtos != null && lockDtos.size() > 0) {
            deviceFlagMapper.bathCreateOrUpdateLockCardByLockDtos(lockDtos);
            return true;
        }
        return false;
    }

    @Override
    public Map<String, Boolean> bathGetDeviceOnline(List<String> imeis) {
        if (imeis == null && imeis.size() > 0) {
            return null;
        }
        Set<String> set = redisService.getKeysByLikePrefix(Constants.DEVICE_ONLINE_PREFIX);
        HashMap<String, Boolean> onlineMap = new HashMap<>();
        for (String imei : imeis) {
            Boolean flag = false;
            for (String key : set) {
                if (key.endsWith(imei)) {
                    flag = true;
                    break;
                }
            }
            onlineMap.put(imei, flag);
        }
        return onlineMap;
    }


    @Override
    public boolean sendLockCard(String imei, int flag, String pin, boolean online, SysUser sysUser) {
        deleteCacheCmd(imei, Constants.LOCK_CARD);
        MqLockCard mqLockCard = new MqLockCard();
        mqLockCard.setImei(imei);
        mqLockCard.setFlag(flag);
        mqLockCard.setCommandNumber(CommandNumberUtil.getCurTime());
        mqLockCard.setPin(pin);
        boolean rest = false;
        try {
            rest = commandSendUtils.setLockCard(mqLockCard, online, sysUser.getUserId(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rest;
    }

    @Override
    public boolean sendLockDevice(String imei, int flag, String iccid, boolean online, SysUser sysUser) {
        deleteCacheCmd(imei, Constants.LOCK_DEVICE);
        MqLockDevice mqLockDevice = new MqLockDevice();
        mqLockDevice.setImei(imei);
        mqLockDevice.setIccid(iccid);
        mqLockDevice.setCommandNumber(CommandNumberUtil.getCurTime());
        mqLockDevice.setFlag(flag);
        boolean rest = false;
        try {
            rest = commandSendUtils.setLockDevice(mqLockDevice, online, sysUser.getUserId(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rest;
    }

    @Override
    public boolean sendLockNet(String imei, int flag, List<Plmn> plmns, boolean online, SysUser sysUser) {
        deleteCacheCmd(imei, Constants.LOCK_NET);
        MqLockNet mqLockNet = new MqLockNet();
        mqLockNet.setImei(imei);
        mqLockNet.setFlag(flag);
        mqLockNet.setCommandNumber(CommandNumberUtil.getCurTime());
        mqLockNet.setPlmns(plmns);
        mqLockNet.setGroupNum(plmns != null ? plmns.size() : 0);
        boolean rest = false;
        try {
            rest = commandSendUtils.setlockNet(mqLockNet, online, sysUser.getUserId(), false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rest;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteCacheCmd(String imei, String cmdPrefix) {
        redisService.deleteHashByPrefix(imei, cmdPrefix);
        return commandRecordService.deleteCacheCmd(imei, cmdPrefix) > 0 ? true : false;
    }

    @Override
    public boolean bathLockDevice(List<BathLockDevice> lockDtos, SysUser sysUser) {
        if (lockDtos != null && lockDtos.size() > 0) {
            threadPool.submit(() -> {
                logger.info("线程: " + Thread.currentThread().getName() + " 开始执行 bathLockDevice " + "执行指令用户id=" + sysUser.getUserId());
                List<String> imeis = lockDtos.stream().map(BathLockDevice::getImei).collect(Collectors.toList());
                Map<String, Boolean> onlines = bathGetDeviceOnline(imeis);
                Iterator<BathLockDevice> iterator = lockDtos.iterator();
                while (iterator.hasNext()) {
                    BathLockDevice lockDto = iterator.next();
                    boolean rest = sendLockDevice(lockDto.getImei(), lockDto.getFlag(), lockDto.getIccid(), onlines.get(lockDto.getImei()), sysUser);
                    if (rest) {
                        lockDto.setFlag(DeviceFlagEnum.getDeviceFlagEnum(lockDto.getFlag()).getStayState());
                    } else {
                        iterator.remove();
                    }
                }
                bathCreateOrUpdateLockDeviceByLockDtos(lockDtos);
                logger.info("线程: " + Thread.currentThread().getName() + "执行结束 bathLockDevice");
            });
        }
        return true;
    }

    @Override
    public boolean bathCreateOrUpdateLockDeviceByLockDtos(List<BathLockDevice> lockDtos) {
        if (lockDtos != null && lockDtos.size() > 0) {
            deviceFlagMapper.bathCreateOrUpdateLockDeviceByLockDtos(lockDtos);
            return true;
        }
        return false;
    }

    @Override
    public List<Plmn> MccMncByPlmns(String plmns, String split) {
        if (StringUtils.isBlank(plmns)) {
            return null;
        }
        String[] plmn = plmns.split(split);
        List<Plmn> plmnList = new ArrayList<>();
        for (int i = 0; i < plmn.length; i++) {
            if (plmn[i].length() < 5) {
                continue;
            }
            Plmn plmn1 = new Plmn();
            plmn1.setMcc(plmn[i].substring(0, 3));
            plmn1.setMnc(plmn[i].substring(3, 5));
            plmnList.add(plmn1);
        }
        return plmnList;
    }

    @Override
    public boolean bathLockNet(List<BathLockNet> lockDtos, List<Plmn> plmnList, SysUser sysUser) {
        if (lockDtos != null && lockDtos.size() > 0) {
            threadPool.submit(() -> {
                logger.info("线程: " + Thread.currentThread().getName() + " 开始执行 bathLockNet " + "执行指令用户id=" + sysUser.getUserId());
                List<String> imeis = lockDtos.stream().map(BathLockNet::getImei).collect(Collectors.toList());
                Map<String, Boolean> onlines = bathGetDeviceOnline(imeis);
                Iterator<BathLockNet> iterator = lockDtos.iterator();
                while (iterator.hasNext()) {
                    BathLockNet lockDto = iterator.next();
                    boolean rest = sendLockNet(lockDto.getImei(), lockDto.getFlag(), plmnList, onlines.get(lockDto.getImei()), sysUser);
                    if (rest) {
                        lockDto.setFlag(DeviceFlagEnum.getDeviceFlagEnum(lockDto.getFlag()).getStayState());
                    } else {
                        iterator.remove();
                    }
                }
                bathCreateOrUpdateLockNetDtos(lockDtos, JSONArray.toJSONString(plmnList));
                logger.info("线程: " + Thread.currentThread().getName() + "执行结束 bathLockNet");
            });
        }
        return true;
    }

    @Override
    public boolean bathCreateOrUpdateLockNetDtos(List<BathLockNet> lockDtos, String plmns) {
        if (lockDtos!=null&&lockDtos.size()>0&&StringUtils.isNotBlank(plmns)){
            deviceFlagMapper.bathCreateOrUpdateLockNetDtos(lockDtos, plmns);
            return true;
        }
        return false;
    }

    @Override
    public boolean lockCardRollBack(Integer deviceId) {
        DeviceFlag deviceFlag = queryDeviceSwitch(deviceId);
        if (deviceFlag != null) {
            if (DeviceFlagEnum.OPEN.getStayState() == deviceFlag.getCardFlag()) {
                deviceFlag.setCardFlag(DeviceFlagEnum.CLOSE.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            } else if (DeviceFlagEnum.CLOSE.getStayState() == deviceFlag.getCardFlag()) {
                deviceFlag.setCardFlag(DeviceFlagEnum.OPEN.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            }
        }
        return true;
    }

    @Override
    public boolean lockDeviceRollBack(Integer deviceId) {
        DeviceFlag deviceFlag = queryDeviceSwitch(deviceId);
        if (deviceFlag != null) {
            if (DeviceFlagEnum.OPEN.getStayState() == deviceFlag.getLockDeviceFlag()) {
                deviceFlag.setLockDeviceFlag(DeviceFlagEnum.CLOSE.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            } else if (DeviceFlagEnum.CLOSE.getStayState() == deviceFlag.getLockDeviceFlag()) {
                deviceFlag.setLockDeviceFlag(DeviceFlagEnum.OPEN.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            }
        }
        return true;
    }

    @Override
    public boolean lockNetRollBack(Integer deviceId) {
        DeviceFlag deviceFlag = queryDeviceSwitch(deviceId);
        if (deviceFlag != null) {
            if (DeviceFlagEnum.OPEN.getStayState() == deviceFlag.getLockNetFlag()) {
                deviceFlag.setLockNetFlag(DeviceFlagEnum.CLOSE.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            } else if (DeviceFlagEnum.CLOSE.getStayState() == deviceFlag.getLockNetFlag()) {
                deviceFlag.setLockNetFlag(DeviceFlagEnum.OPEN.getFlag());
                deviceFlagMapper.updateById(deviceFlag);
            }
        }
        return true;
    }

    @Override
    public BathLockDto dealLockCardData(Integer all, List<Integer> deviceIds, String orgCode) {
        BathLockDto bathLockDto = new BathLockDto();
        if (all == null) {//处理设备集合中数据,设备集合中所有设备必须上锁,除开设备集合中的所有设备全部解锁

        } else if (all == BathLockCardByOrgCodeDto.LOCAK_ALL_DEVICE) {//将客户的设备全部上锁
            //待状态设备不管,查询所有未上锁的设备,进行所有上锁处理

        } else if (all == BathLockCardByOrgCodeDto.UN_LOCK_ALL_DEVICE) {//将客户的设备全部解锁
            // 待状态设备不管,查询所有未上锁的设备,进行所有解锁处理

        }
        return null;
    }


}
